﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace BfLib.Imaging
{
    public class ImageResizer
    {
        private Bitmap _img, _newImage;
        private int _originalWidth=1, _originalHeight=1;
        private int _newWidth=1, _newHeight=1;
        private int _newArea = -1, _originalArea = -1;
        private bool _highQuality = false;

        #region Constructors

        public ImageResizer()
        {

        }
        
        public ImageResizer(string Image)
        {
            _img = new Bitmap(Image);
            _originalWidth = _img.Width;
            _originalHeight = _img.Height;
            _originalArea = _originalWidth * _originalHeight;
        }

        public ImageResizer(byte[] Image)
        {
            //_img = ImageOperator.ByteArrayToBitmap(Image);
            //_originalWidth = _img.Width;
            //_originalHeight = _img.Height;
            //_originalArea = _originalWidth * _originalHeight;
        }

        public ImageResizer(Bitmap Image)
        {
            _img = Image;
            _originalWidth = _img.Width;
            _originalHeight = _img.Height;
            _originalArea = _originalWidth * _originalHeight;
        }

        public ImageResizer(Stream Image)
        {
            _img = new Bitmap(Image);
            _originalWidth = _img.Width;
            _originalHeight = _img.Height;
            _originalArea = _originalWidth * _originalHeight;
        }

        #endregion

        #region Public resizing methods
  
        public void ResizeImage(string Image, int NewWidth, int NewHeight, bool HighQuality)
        {
            if (_img != null)
            {
                _img.Dispose();
            }

            _img = new Bitmap(Image);
            _highQuality = HighQuality;
            _newImage = new Bitmap(NewWidth, NewHeight);
            this._newHeight = NewHeight;
            this._newWidth = NewWidth;

            using (Graphics gr = Graphics.FromImage(_newImage))
            {
                gr.SmoothingMode = SmoothingMode.AntiAlias;

                if (HighQuality)
                {
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                }
                else
                {
                    gr.InterpolationMode = InterpolationMode.Default;
                    gr.PixelOffsetMode = PixelOffsetMode.Default;
                }
                gr.DrawImage(_img, new Rectangle(0, 0, NewWidth, NewHeight));

                _newArea = NewWidth * NewHeight;
            }
        }
        
        public void ResizeImage(byte[] Image, int NewWidth, int NewHeight, bool HighQuality)
        {
            //if (_img != null)
            //{
            //    _img.Dispose();
            //}

            //_img = ImageOperator.ByteArrayToBitmap(Image);
            //_highQuality = HighQuality;
            //_newImage = new Bitmap(NewWidth, NewHeight);
            //this._newHeight = NewHeight;
            //this._newWidth = NewWidth;

            //using (Graphics gr = Graphics.FromImage(_newImage))
            //{
            //    gr.SmoothingMode = SmoothingMode.AntiAlias;

            //    if (HighQuality)
            //    {
            //        gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
            //        gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
            //    }
            //    else
            //    {
            //        gr.InterpolationMode = InterpolationMode.Default;
            //        gr.PixelOffsetMode = PixelOffsetMode.Default;
            //    }
            //    gr.DrawImage(_img, new Rectangle(0, 0, NewWidth, NewHeight));

            //    _newArea = NewWidth * NewHeight;
            //}
        }

        public void ResizeImage(Bitmap Image, int NewWidth, int NewHeight, bool HighQuality)
        {
            if (_img != null)
            {
                _img.Dispose();
            }

            _img = Image;
            _highQuality = HighQuality;
            _newImage = new Bitmap(NewWidth, NewHeight);
            this._newHeight = NewHeight;
            this._newWidth = NewWidth;

            using (Graphics gr = Graphics.FromImage(_newImage))
            {
                gr.SmoothingMode = SmoothingMode.AntiAlias;

                if (HighQuality)
                {
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                }
                else
                {
                    gr.InterpolationMode = InterpolationMode.Default;
                    gr.PixelOffsetMode = PixelOffsetMode.Default;
                }
                gr.DrawImage(_img, new Rectangle(0, 0, NewWidth, NewHeight));

                _newArea = NewWidth * NewHeight;
            }
        }

        public void ResizeImage(Stream Image, int NewWidth, int NewHeight, bool HighQuality)
        {
            if (_img != null)
            {
                _img.Dispose();
            }

            _img = new Bitmap(Image);
            _highQuality = HighQuality;
            _newImage = new Bitmap(NewWidth, NewHeight);
            this._newHeight = NewHeight;
            this._newWidth = NewWidth;

            using (Graphics gr = Graphics.FromImage(_newImage))
            {
                gr.SmoothingMode = SmoothingMode.AntiAlias;

                if (HighQuality)
                {
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                }
                else
                {
                    gr.InterpolationMode = InterpolationMode.Default;
                    gr.PixelOffsetMode = PixelOffsetMode.Default;
                }
                gr.DrawImage(_img, new Rectangle(0, 0, NewWidth, NewHeight));

                _newArea = NewWidth * NewHeight;
            }
        }

        public void ResizeImage(int NewWidth, int NewHeight, bool HighQuality)
        {
            if (_img != null)
            {
                _img.Dispose();
            }

            ValidateOriginalImage();
            _highQuality = HighQuality;
            this._newHeight = NewHeight;
            this._newWidth = NewWidth;

            _newImage = new Bitmap(NewWidth, NewHeight);

            using (Graphics gr = Graphics.FromImage(_newImage))
            {
                gr.SmoothingMode = SmoothingMode.AntiAlias;

                if (HighQuality)
                {
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                }
                else
                {
                    gr.InterpolationMode = InterpolationMode.Default;
                    gr.PixelOffsetMode = PixelOffsetMode.Default;
                }
                gr.DrawImage(_img, new Rectangle(0, 0, NewWidth, NewHeight));

                _newArea = NewWidth * NewHeight;
            }
        }


        public void EnsureMaximumWidth(int MaxWidth, bool HighQuality)
        {
            ValidateOriginalImage();
            _highQuality = HighQuality;

            _newWidth = MaxWidth;
            double scale = Convert.ToDouble(_newWidth) / Convert.ToDouble(_originalWidth);
            _newHeight = Convert.ToInt32(Convert.ToDouble(_originalHeight) * scale);
            ResizeImage(_newWidth, _newHeight, HighQuality);
        }

        public void EnsureMaximumHeight(int MaxHeight, bool HighQuality)
        {
            ValidateOriginalImage();
            _highQuality = HighQuality;

            _newHeight = MaxHeight;
            double scale = Convert.ToDouble(_newHeight) / Convert.ToDouble(_originalHeight);
            _newWidth = Convert.ToInt32(Convert.ToDouble(_originalWidth) * scale);
            ResizeImage(_newWidth, _newHeight, HighQuality);
        }

        public void FitInBox(int BoxWidth, int BoxHeight, bool HighQuality)
        {
            ValidateOriginalImage();
            _highQuality = HighQuality;

            double imgAspect = Convert.ToDouble(_originalWidth) / Convert.ToDouble(_originalHeight);
            double boxAspect = Convert.ToDouble(BoxWidth) / Convert.ToDouble(BoxHeight);
            double scale = 0.0;

            if (imgAspect > boxAspect)
            {
                //will be horizontal in the box, (blank control space above and below)
                _newWidth = BoxWidth;
                scale = Convert.ToDouble(_newWidth) / Convert.ToDouble(_originalWidth);
                _newHeight = Convert.ToInt32(Convert.ToDouble(_originalHeight) * scale);
            }
            else
            {
                //will be vertical in the box, (blank control space left and right)
                _newHeight = BoxHeight;
                scale = Convert.ToDouble(_newHeight) / Convert.ToDouble(_originalHeight);
                _newWidth = Convert.ToInt32(Convert.ToDouble(_originalWidth) * scale);
            }

            ResizeImage(_newWidth, _newHeight, HighQuality);
        }

        public void ScaleImageArea(double Scale, bool HighQuality)
        {
            ValidateOriginalImage();
            _highQuality = HighQuality;

            double scale = Math.Sqrt(Scale);
            _newWidth = Convert.ToInt32(Convert.ToDouble(_originalWidth) * scale);
            _newHeight = Convert.ToInt32(Convert.ToDouble(_originalHeight) * scale);
            ResizeImage(_newWidth, _newHeight, HighQuality);
        }

        public void ScaleImageByDimension(double Scale, bool HighQuality)
        {
            ValidateOriginalImage();
            _highQuality = HighQuality;

            _newWidth = Convert.ToInt32(Convert.ToDouble(_originalWidth) * Scale);
            _newHeight = Convert.ToInt32(Convert.ToDouble(_originalHeight) * Scale);
            ResizeImage(_newWidth, _newHeight, HighQuality);
        }

        #endregion

        #region Private methods
        
        private void ValidateOriginalImage()
        {
            if (this._img == null)
            {
                throw new Exceptions.ImageNullException("Original image object has not been instantiated.");
            }
        }

        #endregion

        #region Public Accessors

        public Bitmap ResultImage
        {
            get
            {
                return _newImage;
            }
        }

        public Bitmap OriginalImage
        {
            get
            {
                return this._img;
            }
        }

        public int AreaOriginal
        {
            get
            {
                return _originalArea;
            }
        }

        public int AreaNew
        {
            get
            {
                return _newArea;
            }
        }

        #endregion
    }
}
